/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#ifndef ONCE_FPARSER_H_
#define ONCE_FPARSER_H_

#include "StlAlgo.h"

/*! Function parser

  \ingroup AlgotoolsGroup
*/
namespace fcnparser
{

	template<typename MapType> typename MapType::const_iterator FindInMap(const MapType& Map, LPCTSTR F)
	{
        unsigned ind = 0;
        while( _istalpha(F[ind]) ) ++ind;
        if(ind)
        {
            std::_tstring name(F, ind);
            return Map.find(name);
		}
		
        return Map.end();
	}

    struct SComp
    {   
		SComp();
        SComp(const SComp& cpy)
		:ByteCode(cpy.ByteCode), ByteCodeSize(cpy.ByteCodeSize),
		Immed(cpy.Immed), ImmedSize(cpy.ImmedSize),
		Stack(new double[cpy.StackSize]), StackSize(cpy.StackSize),
		thisIsACopy(true)
		{};

        ~SComp();

		unsigned* ByteCode;
        unsigned ByteCodeSize;
        double* Immed;
        unsigned ImmedSize;
        double* Stack;
        unsigned StackSize, StackPtr;
        bool thisIsACopy;
    };

    struct FuncDefinition
    {
        unsigned opcode;
        unsigned params;
		
        inline FuncDefinition(unsigned o, unsigned p): opcode(o), params(p) {}
        inline FuncDefinition(): opcode(0), params(1) {}
    };

/*! \brief Function parser for C++  v2.2 by Warp.

\ingroup AlgotoolsGroup

\par Usage license:

<ul>
  <li> This library is free for non-commercial usage. You can do whatever you
     like with it as long as you don't claim you made it yourself.</li>
  <li> It is possible to use this library in a commercial program, but in this
     case you MUST contact me first (warp@iki.fi) and ask express permission
     for this. I want to know what type of program it is going to be, its
     price and so on.
       If you are making a free program or a shareware program with just a
     nominal price (5 US dollars or less), you don't have to ask for
     permission.
       In any case, I DON'T WANT MONEY for the usage of this library. It is
     free, period.</li>
  <li> You can make any modifications you want to it so that it conforms your
     needs. If you make modifications to it, you have, of course, credits for
     the modified parts.</li>
  <li> If you use this library in your own program, you don't have to provide
     the source code if you don't want to (ie. the source code of your program
     or this library).
       If you DO include the source code for this library, this text file
     must be included in its original intact form.</li>
  <li> If you distribute a program which uses this library, and specially if you
     provide the source code, proper credits MUST be included. Trying to
     obfuscate the fact that this library is not made by you or that it is
     free is expressly prohibited. When crediting the usage of this library,
     it's enough to include my nickname and email address, that is:
     "Warp (warp@iki.fi)". Also a URL to the library download page would be
     nice, although not required. The official URL is:
       <a href="http://iki.fi/warp/FunctionParser/">here</a>.
</li>
</ul>
\par What's new in v2.2:
 - Support for long variable names (NOTE: Unfortunately this breaks backwards compatibility.)
 - New functions: min(), max(), if(), eval().
 - Support for recursive calls (with if() and eval()).
 - New operators (mainly for use with if(), but can be used anywhere): '=', '<', '>', '&' and '|'.

\par  What's new in v2.1:
  - Parsing speed optimization.

    I implemented the parser from the scratch using a known parsing algorithm
  from classical compiler techniques, thus replacing my old ad hoc parser.
    The parser should be much faster now, specially with long functions with
  lots of parentheses (specially when the expressions inside parentheses are
  very long).
    I made a test with the function "((2*(5+x*(cos(y-x)/3+2)/4)+1)/4+x)-1" in
  a Sun Ultra 5 computer. The version 2.0 of the library parses it in
  approximately 0.21 ms, while the new version 2.1 parses it in 0.115 ms.
  (I performed the test by parsing the function 100000 times and then dividing
  the total time by that.)
    Needs lots of testing to make sure that it works!

\par  What's new in v2.0:

  - Slight changes in the interface.
    I'm sorry for the lost backwards compatibility, but the v1.x way of taking
    the parameters was just awful - I made it better this time.
    These changes are:
    * Parse() takes the function as a const std::_tstring& (this is fully
      backwards compatible).
    * Parse() takes the variables as a const std::_tstring& (eg. "xy"). The old
      way of taking variable number of parameters was just a too awful hack.
    * The Eval() function taking a variable number of parameters has been
      removed. Although it was a bit easier to use, it was a hack and led to
      inefficient code (internally the parameters were put inside a dynamically
      allocated array anyways, and that's not the most efficient way of doing
      it; it's much more efficient that the user uses a statically allocated
      local array).
    These changes are not radical, so don't get too alarmed. I'm sure that
    changing old code to this new interface is trivial.
  - Added the modulo operator (%) and a new function int().
  - I hope that now, at last, all the problems with parsing functions with
    similar beginnings (eg. acos() vs. acosh()) are gone. Needs more testing,
    though...

\par  What's new in v1.3:

  (Thanks to Roland Schmehl for these bug reports).
  - The library parsed wrongly sinh, cosh and tanh (confused them with sin,
    cos and tan and than reported a syntax error for the 'h').
  - The library parsed an expression like "-cos(x)+cos(y)" like if it
    was "-(cos(x)+cos(y))" instead of "(-cos(x))+cos(y)" as it should. Fixed.
  - The library didn't parse correctly numbers in the form "1e-2". Fixed.
  - Added some explanations at the end of the file.

\par What's new in v1.21:

  - Fixed several memory leaks (thanks to Stephen Agate for the bug report).

\par  What's new in v1.2:

  - If you define the identifier NO_ASINH (see the beginning of fparser.cc),
    then support for the functions asinh, acosh and atanh will be removed
    (they are not part of the ANSI C standard and thus not supported by most
    compilers).
  - A tiny bug fixed.

\par  What's new in v1.1:

  - Fixed bug that made a negated function (eg. "-sin(x)") crash.



\par Preface

  Often people need to ask some mathematical expression from the user and
then evaluate values for that expression. The simplest example is a program
which draws the graphic of a user-defined function on screen.

  This library adds C-style function string parsing to the program. This
means that you can evaluate the string "sqrt(1-x^2+y^2)" with given values
of 'x' and 'y'.

  The library is intended to be very fast. It byte-compiles the function
string at parse time and interpretes this byte-code at evaluation time.
The evaluation is straightforward and no recursions are done (uses stack
arithmetic).
  Empirical tests show that it indeed is very fast (specially compared to
libraries which evaluate functions by just interpreting the raw function
string).

  The library is made in ANSI C++ and requires a standard-conforming C++
compiler.


\par Usage

  To use the CFunctionParser class, you have to include "fparser.h". When
compiling, you have to compile fparser.cpp and link it to the main program.
You can also make a library from the fparser.cpp (see the help on your
compiler to see how this is done).

Example program:

\code
#include "fparser.h"
#include <iostream>

int main()
{
    FunctionParser fp;

    int ret = fp.Parse("x+y-1", "x,y");
    if(ret >= 0)
    {
        std::cerr << "At col " << ret << ": " << fp.ErrorMsg() << std::endl;
        return 1;
    }

    double vals[] = { 4, 8 };

    std::cout << fp.Eval(vals) << std::endl;
}
\endcode

\par The function string

  The function string understood by the class is very similar to the C-syntax.
  Arithmetic float expressions can be created from float literals, variables
or functions using the following operators in this order of precedence:

-   ()             expressions in parentheses first
-   -A             unary minus
-   A^B            exponentiation (A raised to the power B)
-   A*B  A/B  A%B  multiplication, division and modulo
-   A+B  A-B       addition and subtraction
-  A=B  A<B  A>B  comparison between A and B (result is either 0 or 1)
-  A&B            result is 1 if int(A) and int(B) differ from 0, else 0.
-  A|B            result is 1 if int(A) or int(B) differ from 0, else 0.

    Since the unary minus has higher precedence than any other operator, for
  example the following expression is valid: x*-y

  Note that the '=' comparison can be inaccurate due to floating point
 precision problems (eg. "sqrt(100)=10" probably returns 0, not 1).

  The class supports these functions:

-  abs(A)   : Absolute value of A. If A is negative, returns -A otherwise
             returns A.
-  acos(A)  : Arc-cosine of A. Returns the angle, measured in radians,
             whose cosine is A.
-  acosh(A) : Same as acos() but for hyperbolic cosine.
-  asin(A)  : Arc-sine of A. Returns the angle, measured in radians, whose
             sine is A.
-  asinh(A) : Same as asin() but for hyperbolic sine.
-  atan(A)  : Arc-tangent of (A). Returns the angle, measured in radians,
             whose tangent is (A).
-  atanh(A) : Same as atan() but for hyperbolic tangent.
-  ceil(A)  : Ceiling of A. Returns the smallest integer greater than A.
             Rounds up to the next higher integer.
-  cos(A)   : Cosine of A. Returns the cosine of the angle A, where A is
             measured in radians.
-  cosh(A)  : Same as cos() but for hyperbolic cosine.
- eval(...): This a recursive call to the function to be evaluated. The
            number of parameters must be the same as the number of parameters
            taken by the function. Usually called inside if() to avoid
            infinite recursion.
- exp(A)   : Exponential of A. Returns the value of e raised to the power
             A where e is the base of the natural logarithm, i.e. the
             non-repeating value approximately equal to 2.71828182846.
- floor(A) : Floor of A. Returns the largest integer less than A. Rounds
             down to the next lower integer.
- if(A,B,C): If int(A) differs from 0, the return value of this function is B,
            else C. Only the parameter which needs to be evaluated is
            evaluated, the other parameter is skipped; this makes it safe to
            use eval() in them.
- int(A)   : Rounds A to the closest integer. 0.5 is rounded to 1.
  log(A)   : Natural logarithm of A. Returns the natural logarithm base e
             of the value A.
- max(A,B) : If A>B, the result is A, else B.
- min(A,B) : If A<B, the result is A, else B.
-  sin(A)   : Sine of A. Returns the sine of the angle A, where A is
             measured in radians.
-  sinh(A)  : Same as sin() but for hyperbolic sine.
-  sqrt(A)  : Square root of A. Returns the value whose square is A.
-  tan(A)   : Tangent of A. Returns the tangent of the angle A, where A
             is measured in radians.
-  tanh(A)  : Same as tan() but for hyperbolic tangent.


  Examples of function string understood by the class:

\code
  "1+2"
  "x-1"
  "-sin(sqrt(x^2+y^2))"
 "sqrt(XCoord*XCoord + YCoord*YCoord)"
\endcode

 An example of a recursive function is the factorial function:

\code
 "if(n>1, n*eval(n-1), 1)"
\endcode

 Note that a recursive call has some overhead, which makes it a bit slower
 than any other operation. It may be a good idea to avoid recursive functions
 in very time-critical applications. Recursion also takes some memory, so
 extremely deep recursions should be avoided (eg. millions of nested recursive
 calls).

 Also note that the if() function is the only place where making a recursive
 call is safe. In any other place it will cause an infinite recursion (which
 will make the program eventually run out of memory). If this is something
 which should be avoided, it may be a good idea to search the function
 string for 'eval *\(' before giving it to the parser and discard that
 function.


\par Contacting the author

  Any comments, bug reports, etc. should be sent to warp@iki.fi


\par The algorithm used in the library

  The whole idea behind the algorithm is to convert the regular infix
format (the regular syntax for mathematical operations in most languages,
like C and the input of the library) to postfix format. The postfix format
is also called stack arithmetic since an expression in postfix format
can be evaluated using a stack and operating with the top of the stack.

  For example:

\f[ \begin{array}{cc}  \mbox{infix} &\mbox{postfix}\\
  2+3   &   2 3 + \\
  1+2+3  &  1 2 + 3 + \\
  5*2+8/2 & 5 2 * 8 2 / + \\
  (5+9)*3  &5 9 + 3 * \end{array}\f]

  The postfix notation should be read in this way:

  Let's take for example the expression: \f$5 2 * 8 2 / +\f$
  - Put 5 on the stack
  - Put 2 on the stack
  - Multiply the two values on the top of the stack and put the result on
    the stack (removing the two old values)
  - Put 8 on the stack
  - Put 2 on the stack
  - Divide the two values on the top of the stack
  - Add the two values on the top of the stack (which are in this case
    the result of 5*2 and 8/2, that is, 10 and 4).

  At the end there's only one value in the stack, and that value is the
result of the expression.

\par Why stack arithmetic?

  The last example above can give you a hint.
  In infix format operators have precedence and we have to use parentheses to
group operations with lower precedence to be calculated before operations
with higher precedence.
  This causes a problem when evaluating an infix expression, specially
when converting it to byte code. For example in this kind of expression:
    (x+1)/(y+2)
we have to calculate first the two additions before we can calculate the
division. We have to also keep counting parentheses, since there can be
a countless amount of nested parentheses. This usually means that you
have to do some type of recursion.

  The most simple and efficient way of calculating this is to convert it
to postfix notation.
  The postfix notation has the advantage that you can make all operations
in a straightforward way. You just evaluate the expression from left to
right, applying each operation directly and that's it. There are no
parentheses to worry about. You don't need recursion anywhere.
  You have to keep a stack, of course, but that's extremely easily done.
Also you just operate with the top of the stack, which makes it very easy.
You never have to go deeper than 2 items in the stack.
  And even better: Evaluating an expression in postfix format is never
slower than in infix format. All the contrary, in many cases it's a lot
faster (eg. because all parentheses are optimized away).
  The above example could be expressed in postfix format:
    x 1 + y 2 + /

  The good thing about the postfix notation is also the fact that it can
be extremely easily expressed in bytecode form.
  You only need a byte value for each operation, for each variable and
to push a constant to the stack.
  Then you can interpret this bytecode straightforwardly. You just interpret
it byte by byte, from the beginning to the end. You never have to go back,
make loops or anything.

  This is what makes byte-coded stack arithmetic so fast.

*/
class CFunctionParser
{
protected:
    enum OPCODE
    {
			cImmed, cJump,
			cNeg, cAdd, cSub, cMul, cDiv, cMod, cPow,
			cEqual, cLess, cGreater, cAnd, cOr,
			cAbs, cExp, cCeil, cFloor, cLog, cSqrt, cInt,
			cSinh, cCosh, cTanh, cSin, cCos, cTan,
			cAsin, cAcos, cAtan,
			cMin, cMax, cIf,
			cEval,
			VarBegin
    };

public:
    CFunctionParser();
    ~CFunctionParser();

/*! \par Given function

      Parses the given function (and converts it to internal format).
    Destroys previous function. Following calls to Eval() will evaluate
    the given function.
      The strings given as parameters are not needed anymore after parsing.

    \param Function String containing the function to parse.
    \param Vars String containing the variable names, separated by commas. Eg. "x,y" or "VarX,VarY,VarZ,n".

   Variables can have any size and they are case sensitive (ie. "var",
   "VAR" and "Var" are *different* variable names). Only lowercase and
   uppercase letters can be used as variable names. Each variable name
   can appear only once in the string. Function names are not legal variable
   names.

   Using longer variable names causes no overhead whatsoever to the Eval()
   method, so it's completely safe to use variable names of any size.

	\return -1 on success, On error the function returns an index to where the error was found
     (0 is the first character, 1 the second, etc). If the error was not
     a parsing error returns an index to the end of the string + 1.

   Example: 
\code
Parse("3*x+y", "x,y");
\endcode
*/
    int Parse(LPCTSTR Function, LPCTSTR Vars);

	//! returns the number of variables
	unsigned GetVarSize() const					{	return m_iVarAmount;};

	/*! \brief returns error string

    Returns a pointer to an error message string corresponding to the error
    caused by Parse() (you can use this to print the proper error message to
    the user). If no such error has occurred, returns 0.
    */
	LPCTSTR GetParseErrorMsg() const;

	//! \brief returns the function string
	LPCTSTR GetFunction() const			{	return m_sFunction.c_str();};
	//! \brief returns the variables string
	LPCTSTR GetVars() const				{	return m_sVars.c_str();};

	/*! \par Evaluates the function

    Evaluates the function given to #Parse() with the values given to #Eval().
    Each value in the array given to Eval() corresponds to the variables given
    to Parse(). There must be as many values as given to Parse().

    \par Parameters:

    Array of doubles, one for each variable given to the Parse() function.

    \par Return values:
    -On success returns the evaluated value of the function given to
     Parse().
    -On error (such as division by 0) the return value is unspecified,
     probably 0.

    \par Example:

  \code
double Vars[] = {1, -2.5};
double result = Eval(Vars);
\endcode
	  */
	double Eval(const double* Vars) const;


	/*! \brief Used to test if the call to Eval() succeeded.

    Return values:
      If there was no error in the previous call to Eval(), returns 0,
      else returns a positive value as follows:
        1: division by zero
        2: sqrt error (sqrt of a negative value)
        3: log error (logarithm of a negative value)
        4: trigonometric error (asin or acos of illegal value)
		5: not the right number of parameters
	*/
    static LPCTSTR GetEvalErrorMsg(unsigned iEvalErrorType);
private:

    typedef std::map<std::_tstring, FuncDefinition> FuncMap_t;
    typedef std::map<std::_tstring, unsigned> StringMap_t;

    FuncMap_t m_mFunctions;
    StringMap_t m_mVariables;

    FuncMap_t::const_iterator FindFunction(LPCTSTR F)	{	return FindInMap(m_mFunctions, F);};
	StringMap_t::const_iterator FindVariable(LPCTSTR F) {	return FindInMap(m_mVariables, F);};

	std::_tstring m_sVars, m_sFunction;
    int m_iVarAmount, m_iParseErrorType,m_iEvalErrorType;

	SComp Comp;
    int CheckSyntax(LPCTSTR);
    bool Compile(LPCTSTR);
    bool IsVariable(int);
    void AddCompiledByte(unsigned);
    int CompileIf(LPCTSTR, int);
    int CompileElement(LPCTSTR, int);
    int CompilePow(LPCTSTR, int);
    int CompileMult(LPCTSTR, int);
    int CompileAddition(LPCTSTR, int);
    int CompileComparison(LPCTSTR, int);
    int CompileAnd(LPCTSTR, int);
    int CompileOr(LPCTSTR, int);
    int CompileExpression(LPCTSTR, int, bool=false);
	
    // Is given char an operator?
    bool IsOperator(int c)	{return _tcschr(_T("+-/%*^=<>&|,"),c)!=NULL;};

	static const unsigned m_FuncParams[];
	static LPCTSTR m_FuncNames[];
    bool ParseVars(const std::_tstring& Vars);

    CFunctionParser(const CFunctionParser&);
};

};
#endif
